package db;

import busserver.DataProvider;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;

public class DBDataProvider implements DataProvider {
    private BusLib.StationInfo ConvertToStationInfo(Station s) {
        BusLib.Coordinates coord = new BusLib.Coordinates(
                                   s.getLatitude(), s.getLongitude());
        return new BusLib.StationInfo(s.getId(), s.getName(), coord);
    }

    private BusLib.Street ConvertToStreet(Street s) {
        BusLib.Street cs = new BusLib.Street(s.getId(), s.getName());
        ArrayList<Integer> list = new ArrayList<Integer>(s.getLinkStreetses().size());
        ArrayList<StreetPoint> points = new ArrayList<StreetPoint>();

        for(LinkStreets ls : s.getLinkStreetses()) {
            list.add(ls.getStreetPoint().getOrder());
            points.add(ls.getStreetPoint());
        }

        Collections.sort(list);

        for(int i = 0; i < points.size(); i++) {
            StreetPoint point = points.get(list.get(i));
            cs.Points().add(new BusLib.Coordinates(point.getLatitude(),
                                                   point.getLogitude()));
        }

        return cs;
    }

    private BusLib.Link ConvertToLink(Link l) {
        BusLib.Link link = new BusLib.Link(l.getStationByStation1Id().getId(),
                                           l.getStationByStation2Id().getId(),
                                           l.getDistance(), l.getTime());

        for(LinkStreets ls : l.getLinkStreetses()) {
            link.AddStreet(ConvertToStreet(ls.getStreet()));
        }
        
        return link;
    }

    private BusLib.Route ConvertToRoute(Route r) {
        BusLib.Route route = new BusLib.Route(r.getId(), r.getName());

        for(Link l : r.getLinks()) {
            route.AddLink(ConvertToLink(l));
        }

        return route;
    }

    private BusLib.Bus ConvertToBus(Bus b) {
        return new BusLib.Bus(b.getId(), b.getName());
    }

    private BusLib.BusSchedule ConvertToSchedule(Bus b) {
        BusLib.BusSchedule sch = new BusLib.BusSchedule();

        for(BusSchedule s : b.getBusSchedules()) {
            BusLib.StationSchedule ss = new BusLib.StationSchedule(s.getId(),
                                        s.getStation().getId());
            sch.AddStationSchedule(ss);
        }

        return sch;
    }

    private BusLib.Map ConvertToMap(Map m) {
        BusLib.Map map = new BusLib.Map(m.getName(),
                         new BusLib.Coordinates(m.getTopLat(), m.getTopLong()),
                         new BusLib.Coordinates(m.getBottomLat(), m.getBottomLong()),
                         m.getZoomLevels());

        for(Tile t : m.getTiles()) {
            map.Tiles().add(new BusLib.Tile(t.getId(), t.getStartRow(),
                            t.getStartColumn(), t.getLevel()));
        }

        return map;
    }

    public List<BusLib.StationInfo> GetAllStations() {
        List<BusLib.StationInfo> infoList = null;
        List<Station> stations;

        try {
            Session session = HibernateUtil.getSessionFactory().openSession();
            session.beginTransaction();
            Query q = session.createQuery("from Station");
            stations = q.list();
            infoList = new ArrayList<BusLib.StationInfo>();

            for(Station s : stations) {
                BusLib.Coordinates coord = new BusLib.Coordinates(
                                           s.getLatitude(), s.getLongitude());
                infoList.add(new BusLib.StationInfo(s.getId(), s.getName(), coord));
            }

            session.getTransaction().commit();
        } catch (HibernateException he) {
            he.printStackTrace();
        }

        return infoList;
    }

    public BusLib.Station GetStation(int stationId) {
        BusLib.Station station = null;
        HashMap<Integer, Route> routeMap = new HashMap<Integer, Route>();

        try {
            Session session = HibernateUtil.getSessionFactory().openSession();
            session.beginTransaction();
            Query q = session.createQuery("from Station where id=" + stationId);
            Station s = (Station)q.uniqueResult();

            for(Link l : s.getLinksForStation1Id()) {
                routeMap.put(l.getRoute().getId(), l.getRoute());
            }

            for(Link l : s.getLinksForStation2Id()) {
                routeMap.put(l.getRoute().getId(), l.getRoute());
            }

            station = new BusLib.Station(s.getId(), s.getName(), s.getStreetName(),
                                        new BusLib.Coordinates(s.getLatitude(),
                                        s.getLongitude()));

            for(Route r : routeMap.values()) {
               station.AddRoute(ConvertToRoute(r));
            }

            session.getTransaction().commit();
        } catch (HibernateException he) {
            he.printStackTrace();
        }

        return station;
    }

    public BusLib.Bus GetBusOnRoute(int routeId) {
        BusLib.Bus bus = null;

        try {
            Session session = HibernateUtil.getSessionFactory().openSession();
            session.beginTransaction();
            Query q = session.createQuery("from Bus where routeId=" + routeId);
            Bus b = (Bus)q.uniqueResult();
            bus = ConvertToBus(b);
            session.getTransaction().commit();
        } catch (HibernateException he) {
            he.printStackTrace();
        }

        return bus;
    }

    public BusLib.BusSchedule GetBusSchedule(int busId) {
        BusLib.BusSchedule sch = null;

         try {
            Session session = HibernateUtil.getSessionFactory().openSession();
            session.beginTransaction();
            Query q = session.createQuery("from Bus where id=" + busId);
            Bus b = (Bus)q.uniqueResult();
            sch = ConvertToSchedule(b);
            session.getTransaction().commit();
        } catch (HibernateException he) {
            he.printStackTrace();
        }

        return sch;
    }

    public BusLib.Map GetMap() {
        BusLib.Map map = null;

         try {
            Session session = HibernateUtil.getSessionFactory().openSession();
            session.beginTransaction();
            Query q = session.createQuery("from Map");
            List<Map> list = q.list();
            map = ConvertToMap(list.get(0));
            session.getTransaction().commit();
        } catch (HibernateException he) {
            he.printStackTrace();
        }

        return map;
    }

    public String GetTilePath(int tileId) {
        String file = null;

         try {
            Session session = HibernateUtil.getSessionFactory().openSession();
            session.beginTransaction();
            Query q = session.createQuery("from Tile where id=" + tileId);
            Tile t = (Tile)q.uniqueResult();
            file = t.getFile();
            session.getTransaction().commit();
        } catch (HibernateException he) {
            he.printStackTrace();
        }

        return file;
    }
}
